package com.example.common.event

import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import java.lang.NullPointerException
/**
 * 自定义LiveDataBus
 *
 * 理由：相对于EventBus来对比
 *     1.EventBus 需要添加注册，反注册，提供接收事件方法
 *     2.还要自己管理生命周期（手动注册和取消注册），容易导致内存泄漏
 *
 * LiveData优势：
 *     1.本来设计上是支持粘性事件（有缓存，有数据版本控制），但是不支持非粘性（不足）
 *     2.自动关联组件的生命周期
 *
 * 如何解决LiveData的非粘性事件（数据倒灌问题）
 *     1.Google推荐使用SingleLiveEvent（不支持多次订阅）
 *     2.UnPeekLiveData (支持多次订阅)
 *     3.使用反射技术修改订阅版本号和数据版本号，阻止通知订阅方更新数据
 *     4.使用后ShareFlow共享热流
 */


/**
 * 使用观察者的设计模式（观察-订阅）
 * 接入了Jetpack时推荐
 */
object LiveDataBus {

    /**
     * 不同业务对应不同的BusMutableLiveData
     */
    private val bus: MutableMap<String, BusMutableLiveData<Any>> = mutableMapOf()

    fun <T> getDefault(key: String): BusMutableLiveData<T>{
        if (!bus.containsKey(key)){
            bus[key] = BusMutableLiveData()
        }
        return bus[key] as BusMutableLiveData<T>
    }


    /**
     * 自定义LiveData，利用反射技术修改订阅版本号和数据版本号，解决非粘性问题（LiveData本身属于粘性设计，会导致数据倒灌问题）
     */
    class BusMutableLiveData<T>: MutableLiveData<T>(){

        //存储所有订阅方
        private val observerMap: MutableMap<Observer<*>, Observer<*>> = mutableMapOf()

        /**
         * 订阅前台事件
         */
        override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
            super.observe(owner, observer)
            try {
                hookSticky(observer)
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }

        /**
         * 订阅前台粘性事件
         */
        fun observerSticky(owner: LifecycleOwner, observer: Observer<in T>){
            //本身支持粘性事件，所以不用做处理
            super.observe(owner, observer)
        }


        /**
         * 订阅后台事件
         */
        override fun observeForever(observer: Observer<in T>) {
            if (!observerMap.containsKey(observer)){
                observerMap[observer] = ObserverWrapper(observer)
            }
            super.observeForever(observerMap[observer] as Observer<in T>)
        }

        /**
         * 订阅后台粘性事件
         */
        fun observeForeverSticky(observer: Observer<in T>) {
            super.observeForever(observer)
        }

        /**
         * 移除订阅方
         */
        override fun removeObserver(observer: Observer<in T>) {
            val observerWrapper: Observer<in T> = if (observerMap.containsKey(observer)){
                observerMap.remove(observer) as Observer<in T>
            } else {
                observer
            }
            super.removeObserver(observerWrapper)
        }

        /**
         * 利用反射技术，修改版本号
         */
        private fun hookSticky(observer: Observer<*>){
            //获取LiveData的Class字节码文件
            val liveDataClass = LiveData::class.java
            //获取订阅版本号
            val mVersionField = liveDataClass.getDeclaredField("mVersion").apply {
                isAccessible = true
            }
            var observerVersion = mVersionField[this]

            //获取所有订阅方集合
            val mObserverFieldMap = liveDataClass.getDeclaredField("mObservers").apply {
                isAccessible = true
            }
            val observers = mObserverFieldMap[this]

            //获取集合的Class对象
            val observerClass: Class<*> = observers.javaClass
            val methodGet = observerClass.getDeclaredMethod("get", Any::class.java).apply {
                isAccessible = true
            }

            //执行GET方法
            val observerObject = methodGet.invoke(observers, observer)
            var subObserverWrapper: Any? = null
            if (observerObject is Map.Entry<*, *>){
                subObserverWrapper = observerObject.value
            }

            //做判空处理
            if (subObserverWrapper == null){
                throw NullPointerException("Observer Wrapper not is null!")
            }

            //获取父类Class文件
            val observerWrapperClass: Class<*>? = subObserverWrapper.javaClass.superclass
            //获取数据版本号
            val lastVersionField = observerWrapperClass!!.getDeclaredField("mLastVersion").apply {
                isAccessible = true
            }

            //修改数据版本号
            lastVersionField[subObserverWrapper] = observerVersion
        }

    }


    class ObserverWrapper<T>(private val observer: Observer<T>): Observer<T>{

        override fun onChanged(value: T) {
            if (isCallOnObserverForever()) return
            observer.onChanged(value)
        }

        private fun isCallOnObserverForever(): Boolean{
            val threadStack = Thread.currentThread().stackTrace
            for (item in threadStack){
                if ("androidx.lifecycle.LiveData" == item.className && "observeForever" == item.methodName) {
                    return true
                }
            }
            return false
        }

    }

}